package com.components.base.view.tiktok

import android.animation.*
import android.animation.ValueAnimator.AnimatorUpdateListener
import android.content.Context
import android.graphics.Bitmap
import android.graphics.PointF
import android.graphics.drawable.Drawable
import android.os.Message
import android.util.AttributeSet
import android.view.View
import android.view.animation.AccelerateInterpolator
import android.widget.ImageView
import android.widget.RelativeLayout
import com.components.base.R
import com.components.base.utils.dpx
import java.util.*

class TikTokMusicalNoteLayout :
    RelativeLayout, WeakWrapperHandler.MessageHandler {
    // layout的宽高
    private var mWidth = 0
    private var mHeight = 0

    // 音符Drawable集合
    private var mDrawables: MutableList<Drawable>? = null

    // 音符的宽高
    private var mDrawableWidth = 0
    private var mDrawableHeight = 0

    // 音符LayoutParams
    private var mNoteParams: LayoutParams? = null

    // 转圈的音乐view
    private var mMusicView: TikTokCircleMusicView? = null
    private var mIndex = 0
    private val mRandom = Random()
    private var mAnimateHandler: WeakWrapperHandler? = null

    constructor(context: Context) : this(context, null, 0)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        init(context, attrs)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mWidth = w
        mHeight = h
        // test code
        start(true)
    }


    private fun init(context: Context, attrs: AttributeSet?) {
        mAnimateHandler = WeakWrapperHandler(this)
        val defaultSize = DEFAULT_MUSIC_VIEW_SIZE.dpx
        val musicViewSize: Int
        val musicViewRes: Drawable?
        val ta = context.obtainStyledAttributes(attrs, R.styleable.tiktokMusicalNoteLayout, 0, 0)
        try {
            musicViewSize = ta.getDimensionPixelOffset(
                R.styleable.tiktokMusicalNoteLayout_tiktok_music_view_size,
                defaultSize
            )
            musicViewRes = ta.getDrawable(R.styleable.tiktokMusicalNoteLayout_tiktok_music_view_res)
        } finally {
            ta.recycle()
        }
        mMusicView = TikTokCircleMusicView(getContext())
        mMusicView?.setImageDrawable(musicViewRes)
        mMusicView?.id = R.id.tiktok_music_view_id
        val params = LayoutParams(musicViewSize, musicViewSize)
        params.addRule(ALIGN_PARENT_BOTTOM)
        params.addRule(ALIGN_PARENT_RIGHT)
        params.rightMargin = 10.dpx
        params.bottomMargin = 25.dpx
        addView(mMusicView, params)
        val note1 = resources.getDrawable(R.drawable.tiktok_icon_note1)
        val note2 = resources.getDrawable(R.drawable.tiktok_icon_note2)
        mDrawables = ArrayList()
        for (i in 0..2) {
            mDrawables?.add(if (i == 0) note1 else note2)
        }
        mDrawableHeight = note1.intrinsicHeight / 2
        mDrawableWidth = note1.intrinsicWidth / 2
        mNoteParams = LayoutParams(mDrawableWidth, mDrawableHeight)
        mNoteParams!!.addRule(ALIGN_PARENT_BOTTOM)
        mNoteParams!!.addRule(ALIGN_PARENT_RIGHT)
        mNoteParams!!.rightMargin = params.rightMargin + musicViewSize / 2 - mDrawableWidth / 2
        mNoteParams!!.bottomMargin = params.bottomMargin - mDrawableHeight
    }

    fun start(start: Boolean) {
        mAnimateHandler!!.removeMessages(MSG_WHAT_ROTATION)
        mAnimateHandler!!.removeMessages(MSG_WHAT_ADD_NOTE)
        if (start) {
            mAnimateHandler!!.sendEmptyMessage(MSG_WHAT_ROTATION)
            mAnimateHandler!!.sendEmptyMessage(MSG_WHAT_ADD_NOTE)
        }
    }

    fun setImageResource(resId: Int) {
        mMusicView?.setImageResource(resId)
    }

    fun setImageBitmap(bm: Bitmap) {
        mMusicView?.setImageBitmap(bm)
    }

    override fun handleMessage(msg: Message?) {
        if (msg?.what == MSG_WHAT_ROTATION) {
            mMusicView?.startRotate()
            mAnimateHandler!!.sendEmptyMessageDelayed(
                MSG_WHAT_ROTATION,
                DEFAULT_ROTATION_SPEED.toLong()
            )
        } else if (msg?.what == MSG_WHAT_ADD_NOTE) {
            ++mIndex
            if (mIndex >= mDrawables!!.size) {
                mIndex = 0
            }
            addMusicNote(mIndex)
            mAnimateHandler!!.sendEmptyMessageDelayed(
                MSG_WHAT_ADD_NOTE,
                DEFAULT_ADD_NOTE_SPEED.toLong()
            )
        }
    }

    private fun addMusicNote(index: Int) {
        val noteView = ImageView(context)
        noteView.setImageDrawable(mDrawables!![index])
        addView(noteView, mNoteParams)
        val set = getFinalAnimator(noteView)
        set.addListener(AnimEndListener(noteView))
        set.start()
    }

    private fun getFinalAnimator(target: View): Animator {
        val set = getEnterAnimator(target)
        val bezierValueAnimator = getBezierValueAnimator(target)
        val finalSet = AnimatorSet()
        finalSet.playTogether(set, bezierValueAnimator)
        finalSet.interpolator = AccelerateInterpolator()
        finalSet.setTarget(target)
        return finalSet
    }

    // 出场动画
    private fun getEnterAnimator(target: View): AnimatorSet {
        val alpha = ObjectAnimator.ofFloat(target, ALPHA, 0.1f, 1f)
        val scaleX = ObjectAnimator.ofFloat(target, SCALE_X, 0.0f, 1f)
        val scaleY = ObjectAnimator.ofFloat(target, SCALE_Y, 0.0f, 1f)
        val enter = AnimatorSet()
        enter.duration = 1000
        enter.interpolator = AccelerateInterpolator()
        enter.playTogether(alpha, scaleX, scaleY)
        val before = AnimatorSet()
        // 同时在正负25f的角度上做随机旋转
        val rotate = ObjectAnimator.ofFloat(target, ROTATION, 0.0f, mRandom.nextInt(50) - 20f)
        rotate.duration = 2000
        before.playSequentially(enter, rotate)
        return before
    }

    // 贝塞尔曲线轨迹动画
    private fun getBezierValueAnimator(target: View): ValueAnimator {
        // 中点
        val evaluator = BezierEvaluator(
            PointF(0f, (mHeight - mHeight / 4).toFloat()),
            PointF(0f, (mHeight - mHeight / 2).toFloat())
        )
        // 终点在0
        // 起点定在音符的左上角坐标
        val animator = ValueAnimator.ofObject(
            evaluator,
            PointF(
                mMusicView!!.x + mMusicView!!.width / 2 - mDrawableHeight / 2,
                mMusicView!!.bottom.toFloat()
            ),
            PointF(
                (mMusicView!!.left / 2).toFloat(),
                (mMusicView!!.top - mMusicView!!.height / 2).toFloat()
            )
        )
        animator.addUpdateListener(BezierListener(target))
        animator.duration = 4000
        return animator
    }

    private inner class BezierListener(private val target: View) :
        AnimatorUpdateListener {
        override fun onAnimationUpdate(va: ValueAnimator) {
            val pointF = va.animatedValue as PointF
            target.x = pointF.x
            target.y = pointF.y
            target.alpha = 1 - va.animatedFraction
        }
    }

    private inner class AnimEndListener(private val target: View) :
        AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            super.onAnimationEnd(animation)
            removeView(target)
        }
    }

    companion object {
        private const val DEFAULT_MUSIC_VIEW_SIZE = 45 //dp
        private const val MSG_WHAT_ROTATION = 0
        private const val MSG_WHAT_ADD_NOTE = 1
        private const val DEFAULT_ROTATION_SPEED = 50
        private const val DEFAULT_ADD_NOTE_SPEED = 800
    }

}
